<?php

class PasswordHashDriver {
    const MD5=0;
    const SHA1=1;
    const DEFAULT_LENGTH=8;
    const DEFAULT_DELIMITER="_";
    
    protected $_method;
    protected $_saltLength;
    protected $_delimiter;
    
    public function __construct($method=self::MD5, $length=self::DEFAULT_LENGTH, $delimiter=self::DEFAULT_DELIMITER) {
        $this->hashMethod($method);
        $this->saltLength($length);
        $this->delimiter($delimiter);
    }
    
    public function delimiter($delimiter=null) {
        $old = $this->_delimiter;
    
        if($delimiter!==null) {
            $this->_delimiter = $delimiter;
        }
    
        return $old;
    }
    
    public function hashMethod($method=null) {
        $old = $this->_method;
        
        if($method!==null) {
            $this->_method = $method;
        }
        
        return $old;
    }
    
    public function saltLength($length=null) {
        $old = $this->_saltLength;
        
        if($length!==null) {
            $this->_saltLength = $length;
        }
        
        return $old;
    }
    
    public function hash($password) {
        if($this->_saltLength) {
            $salt = $this->_generateSalt();
        } else {
            $salt = "";
        }
        
        return $this->_hash($password, $salt);
    }
    
    protected function _hash($password, $salt, $method=null) {
        $saltLength = strlen($salt);
        $password = substr($salt, 0, intval($saltLength/2)) . $password . substr($salt, intval($saltLength/2));
        $salt = $salt ? ("$salt" . $this->_delimiter) : "";
    
        $method = $method ? $method : $this->_method;
        
        switch ($method) {
            case self::SHA1:
                return $salt . sha1($password) . self::SHA1;
            case self::MD5:
            default:
                return $salt . md5($password) . self::MD5;
        }
    }
    
    public function verify($password, $hashPassword) {
        $pos = strpos($hashPassword, $this->_delimiter);
        $method = intval(substr($hashPassword, -1));
        $salt = "";
        
        if($pos !== false) {
            $salt = substr($hashPassword, 0, $pos);
        }
    
        return $hashPassword == $this->_hash($password, $salt, $method);
    }
    
    protected function _generateSalt() {
        $m = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $l = strlen($m);
        $salt = "";
        
        for($i=0; $i<$this->_saltLength; $i++) {
            $salt .= $m[mt_rand(0, $l-1)];
        }
        
        return $salt;
    }
}

$hashDriver = new PasswordHashDriver();
echo $hashDriver->hash('123456') . "\n";

var_dump($hashDriver->verify('123456', 'wDrOtyTN_bf04aa35520bd119da1756c0d9e017590'));